﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;

namespace Vibz.Common.Sequential
{
    [Serializable]
    public class ElementSequence : List<IElement>, IXmlSerializable
    {
        [XmlIgnore]
        public IElement First { get { if (this.Count > 0) return this[0]; else return null; } }
        public ElementSequence()
        { }
        public void AddLast(IElement element)
        {
            this.Add(element);
            element.Sequence = this;
        }
        public void AddFirst(IElement element)
        {
            this.Insert(0, element);
            element.Sequence = this;
        }
        public void AddAfter(IElement refElement, IElement elementToAdd)
        {
            if (!this.Contains(refElement))
                throw new Exception("Reference element is not in same sequence.");
            this.Insert(this.IndexOf(refElement) + 1, elementToAdd);
            elementToAdd.Sequence = this;
        }
        public void AddBefore(IElement refElement, IElement elementToAdd)
        {
            if (!this.Contains(refElement))
                throw new Exception("Reference element is not in same sequence.");
            this.Insert(this.IndexOf(refElement), elementToAdd);
            elementToAdd.Sequence = this;
        }
        public IElement PreviousOf(IElement element)
        {
            IElement retValue = null;
            if (!this.Contains(element))
                throw new Exception("Reference element is not in same sequence.");

            if (this.IndexOf(element) > 0)
                retValue = this[this.IndexOf(element) - 1];

            return retValue;
        }
        public IElement NextTo(IElement element)
        {
            IElement retValue = null;
            if (!this.Contains(element))
                throw new Exception("Reference element is not in same sequence.");

            if (this.IndexOf(element) < this.Count - 1)
                retValue = this[this.IndexOf(element) + 1];

            return retValue;
        }
        #region XML Serialization
        public System.Xml.Schema.XmlSchema GetSchema() { return null; }

        public void ReadXml(XmlReader reader)
        {
            try
            {
                if (reader.IsEmptyElement)
                    return;
                
                reader.ReadStartElement("sq");
                while (reader.IsStartElement("e"))
                {
                    Type type = Type.GetType(reader.GetAttribute("aqn"));
                    XmlSerializer serial = new XmlSerializer(type);

                    reader.ReadStartElement("e");
                    IElement ele = (IElement)serial.Deserialize(reader);
                    ele.Sequence = this;
                    this.Add(ele);
                    reader.ReadEndElement();
                }
                reader.ReadEndElement();
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                throw;
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            try
            {
                foreach (IElement dispatcher in this)
                {
                    writer.WriteStartElement("e");
                    writer.WriteAttributeString("aqn", dispatcher.GetType().AssemblyQualifiedName);
                    XmlSerializer xmlSerializer = new XmlSerializer(dispatcher.GetType());
                    xmlSerializer.Serialize(writer, dispatcher);
                    writer.WriteEndElement();
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                throw;
            }
        }
        #endregion
    }
}
